import { NAME, WIDTHLOADING, EASING } from './data';

interface Pos { x: number, y: number };
interface BoundFrame {
    left: number; top: number; right: number; bottom: number;
}
interface ControlTransform extends Pos, BoundFrame {
    scale: number;
    width: number;
    height: number;
};
const defaultControlTransform = () => {
    return {
        x: 0, y: 0, scale: 1, left: 0, top: 0,
        right: 0, bottom: 0, width: 0, height: 0
    } as ControlTransform;
}
type TouchPos = Pos & {
    timestamp: number,  // 
    diameter: number    // distance between two touch point
};

const constant = {
    fps: 60,
    duration: 300,
    ratio: 250,
};

function debugoutput(content: string) {
    document.getElementById('debug').innerHTML = content + "";
}


interface TypeEngine {
    page: number;
    pageItem: HTMLElement;

    wrapper: HTMLDivElement;
    wrapperBound: ControlTransform;
    el: HTMLDivElement;
    // 
    // elCenterPos: Pos;
    // Control Element Translate Property ready to update
    elProperties: ControlTransform;
    // First Image suitable Translate, record at init
    posElInit: ControlTransform;
    posItemInit: ControlTransform;
    // Translate property For Position Calculate expediently 
    // when touch start(move in touch start, pinch in touch move) 
    lastTouchStartElPos: ControlTransform;
    // Ending animation variable.
    lastTouchStartPos: TouchPos[];

    lastTouchStartItemBound: ControlTransform;
    // Previous event's touch position; 
    lastTouchPos: TouchPos[];
    // Previous event's touch center for ending; 
    lastCenterPosDiff: TouchPos;
    // For Funciton Scale
    scaleStartCenter: TouchPos
    // For Funciton Scale
    scaleOriginDiff: Pos;
    // For Funciton Scale
    scaleLastTouchCenter: TouchPos;
    intervalEnding: number;
    timeoutDouble: number;
    // fix out of bound
    flagOutOfBound: boolean;
    // offsetBoundFix: Pos;

    // setting
    options: {
        pinch: boolean;
        pinchMin: number;
        pinchMax: number;
        ending: boolean;
    };

    init(): void;
    initPos(): void;
    fnHeader(s: string): void;
    bindEvent(wrapper: HTMLDivElement): void;
    onHeader(fn: (s: string) => void): void;
    zoom(times: number, touchPos?: TouchPos): void;
    move(touchPos: TouchPos[]): void;
    scaleScriptBefore(pos: Pos): void;
    scaleEventBefore(touchPos: TouchPos[]): void;
    scale(touchPos: TouchPos[], diffScale?: number): void;
    endMotion(endTouchPos: TouchPos[]): void;
    endMotionHandleSwipe(dir: boolean): void;
    endMotionScale(): void;
    endMotionHandleSlide(speedX: number, speedY: number): void;
    endMotionHandleSlideEnd(): void;
    fixInBound(): boolean;
    updateElPos(): void;
    // getImageBounding(index: number): Pos[];
    withAnimate(): void;
    animateEnd(): void;

    emmitJumpPage(pageNum: number): void;
    pager: {
        count(): number;
        to(pageNum: number, withoutAnimate?: boolean): void;
        zoom(scale: number): void;
    };
    event: {
        moving: boolean;
        scaling: boolean;
        jumping: boolean;
        clearDoingType(): void;
        // transiting: boolean;
        start(e: TouchEvent): void;
        move(e: TouchEvent): void;
        end(e: TouchEvent): void;
        double(tp: TouchPos): void;
        transitionEnd(e: TransitionEvent): void;
    };
    util: {
        getRect(el: HTMLElement): DOMRect;
        getElPos(el: HTMLElement): ControlTransform;
        getTouchesPos(e: TouchEvent): TouchPos[];
        // offsetPosWithEl(touchPos: TouchPos, lastPos?: TouchPos): Pos;
        offsetCenterDiff(newPos: TouchPos[], lastPos: TouchPos[]): TouchPos;
        getGestureCenterPos(touchPos: TouchPos[]): TouchPos;
        getItem(pageNum?: number): HTMLElement;
        getPosFixOutOfBound(elPro: ControlTransform, nextPos: Pos, fixBound: ControlTransform): boolean;
        getPosFixOutOfBoundAtEnding(fixBound: ControlTransform): Pos;
        numberLevelDown(num: number, max: number): number;
        diffInFixBound(): BoundFrame; 
    }
}

const engine: TypeEngine = {
    page: 1,
    pageItem: null,
    wrapper: null,
    wrapperBound: defaultControlTransform(),
    el: null,
    // elBounding: {} as DOMRect, 
    // scale center
    // elCenterPos: { x: 0, y: 0 },
    // El transform properties.
    // for render.
    elProperties: defaultControlTransform(),
    posElInit: defaultControlTransform(),
    posItemInit: defaultControlTransform(),
    // El transform properties when touch start
    // with scale function.
    lastTouchStartElPos: defaultControlTransform(),
    // Position in event touch start.
    lastTouchStartPos: [],
    lastTouchStartItemBound: defaultControlTransform(),
    // previous touches
    lastTouchPos: [],
    // For move, it is for ending animation.
    lastCenterPosDiff: { x: 0, y: 0, timestamp: 0, diameter: 0 },
    // For scale, it is for different between el center position and touch point position.
    // scaleCenterPosDiff: { x: 0, y: 0 } as Pos,
    // scaling: false,
    // animation interval
    scaleStartCenter: { x: 0, y: 0, timestamp: 0, diameter: 0 },
    scaleOriginDiff: { x: 0, y: 0},
    scaleLastTouchCenter: { x: 0, y: 0, timestamp: 0, diameter: 0 },
    intervalEnding: 0,
    timeoutDouble: 0,
    flagOutOfBound: false,

    options: {
        pinch: true,
        pinchMin: 1,
        pinchMax: 5,
        ending: true,
    },

    fnHeader(s: string) { },

    bindEvent(wrapper: HTMLDivElement) {
        engine.page = 0;
        const el = <HTMLDivElement>wrapper.querySelector(`div.${NAME.CSS_CONTROL}`);
        el.addEventListener('touchstart', engine.event.start);
        el.addEventListener('touchmove', engine.event.move);
        el.addEventListener('touchend', engine.event.end);
        el.addEventListener('transitionend', engine.event.transitionEnd);
        engine.wrapper = wrapper;
        engine.wrapperBound = engine.util.getElPos(engine.wrapper);
        engine.el = el;
        Object.assign(engine.elProperties, engine.util.getElPos(el));
    },

    init() {
        // engine.wrapper.classList.remove(NAME.CSS_LOADING);
        engine.posElInit = engine.util.getElPos(engine.el); // need some variable for page jump.
        engine.pager.to(engine.page, true);   // Set true to skip animation.
        // Rewrite position when first image in the middle of the box.
        engine.initPos();
    },

    initPos() {
        engine.posElInit = engine.util.getElPos(engine.el);
        // engine.posItemInit = engine.util.getElPos(engine.util.getItem());
        // when resize
        engine.pager.to(engine.page, true);   // Set true to skip animation.
        // fix bound size wrapper after resize
        engine.posItemInit = engine.util.getElPos(engine.util.getItem());
    },

    onHeader(fnHeader: typeof engine.fnHeader) {
        engine.fnHeader = fnHeader;
    },

    zoom(times: number, touchPos?: TouchPos) {
        if (!touchPos) {
            const boundingWrap = engine.wrapperBound;
            touchPos = {
                x: boundingWrap.left + boundingWrap.width / 2,
                y: boundingWrap.top + boundingWrap.height / 2,
                timestamp: 0, diameter: 0 
            };
        }
        engine.scaleScriptBefore(touchPos);
        engine.withAnimate();
        engine.scale([touchPos], times);
    },

    move(touchPos: TouchPos[]) {
        let x = touchPos[0].x - engine.lastTouchPos[0].x + engine.elProperties.x;
        let y = touchPos[0].y - engine.lastTouchPos[0].y + engine.elProperties.y;
        x = Math.round(x);
        y = Math.round(y);
        const nextElProperties = { x, y };

        engine.flagOutOfBound = engine.util.getPosFixOutOfBound(
            engine.elProperties, nextElProperties, engine.posItemInit);
        Object.assign(engine.elProperties, nextElProperties);
        engine.updateElPos();
    },

    scaleScriptBefore(pos: Pos) {
        engine.scaleStartCenter = { ...pos, timestamp: 0, diameter: 0 };
        // const boundingCtrl: DOMRect = engine.el.getBoundingClientRect();
        const boundingCtrl: DOMRect = engine.util.getRect(engine.el);
        Object.assign(engine.lastTouchStartElPos, engine.elProperties);
        engine.scaleOriginDiff = {
            // pageX - originX
            x: engine.scaleStartCenter.x - (boundingCtrl.width / 2 + boundingCtrl.left),
            y: engine.scaleStartCenter.y - (boundingCtrl.height / 2 + boundingCtrl.top),
        };
    },

    scaleEventBefore(touchPos) {
        engine.scaleStartCenter = engine.util.getGestureCenterPos(touchPos);
        // Touch start event only listene one touche,
        // fix two touche recording here.
        Object.assign(engine.lastTouchStartElPos, engine.elProperties);
        // engine.lastTouchStartPos = touchPos;
        // Confirm scale origin.
        // const boundingCtrl: DOMRect = engine.el.getBoundingClientRect();
        const boundingCtrl: DOMRect = engine.util.getRect(engine.el);
        engine.scaleOriginDiff = {
            // pageX - originX
            x: engine.scaleStartCenter.x - (boundingCtrl.width / 2 + boundingCtrl.left),
            y: engine.scaleStartCenter.y - (boundingCtrl.height / 2 + boundingCtrl.top),
        };
    },

    scale(touchPos: TouchPos[], diffScale?: number) {
        if (engine.lastTouchPos.length == 0 && diffScale == null) {
            return;
        }
        // Touch start status
        const tpStart = engine.scaleStartCenter;
        const tpNow = engine.util.getGestureCenterPos(touchPos);
        // record this position for minimum check at the ending.
        engine.scaleLastTouchCenter = tpNow;
        // May define scale from outside.
        diffScale = diffScale || tpNow.diameter / tpStart.diameter;
        // Image it was scale and move allway from the touch start.
        const propToUpdate = engine.elProperties;
        let scale = engine.lastTouchStartElPos.scale * diffScale;

        // Check minimum scale, make small zoom hard.
        if (scale < engine.options.pinchMin) {
            scale = engine.options.pinchMin - (engine.options.pinchMin - scale) * 0.4;
            diffScale = scale / engine.lastTouchStartElPos.scale;
        }

        const diffStartNow = engine.util.offsetCenterDiff([tpNow], [tpStart]);

        propToUpdate.scale = scale;
        propToUpdate.x = engine.lastTouchStartElPos.x
            - engine.scaleOriginDiff.x * (diffScale - 1)
            + diffStartNow.x;
        propToUpdate.y = engine.lastTouchStartElPos.y
            - engine.scaleOriginDiff.y * (diffScale - 1)
            + diffStartNow.y;
        engine.updateElPos();
    },

    /**
     * turn to next/prev page on
     * 1. frame move over 30% width
     * k
     * 2. swipe speed up to 20px in 1ms
     * @param endTouchPoses 
     */
    endMotion(endTouchPoses: TouchPos[]) {
        const diff = engine.lastCenterPosDiff;
        const speedX = diff.x / diff.timestamp;
        const speedY = diff.y / diff.timestamp;
        // turn page in a lower scale value
        const flagSpeedJumpInScale = engine.elProperties.scale < 1.5;
        // check vertical swipe not too much
        const flagSpeedLimitY = Math.abs(engine.lastTouchStartPos[0].y - engine.lastTouchPos[0].y)
            < engine.posItemInit.height * 0.15;
        // check if it can swipe whether swipe enough;
        const swipeLongJump = engine.lastTouchStartPos[0].x - engine.lastTouchPos[0].x;
        const flagSwipeLongJump = Math.abs(swipeLongJump) > engine.posItemInit.width * 0.35;
        // speed enougth
        // scale = 1
        if (flagSpeedJumpInScale && Math.abs(speedX) > 0.5 && flagSpeedLimitY) {
            engine.endMotionHandleSwipe(diff.x < 0);
            // swipe distance engouth
        // } else if (Math.abs(diff.x) > (engine.initItemPos.width * 0.12)) {
        } else if (flagSwipeLongJump && engine.flagOutOfBound && flagSpeedLimitY) {
            engine.endMotionHandleSwipe(swipeLongJump > 0);
        } else if (engine.flagOutOfBound) {
            engine.fixInBound();
        // sliding
        } else {
            engine.endMotionHandleSlide(speedX, speedY);
        }
    },

    endMotionHandleSwipe(dir) {
        engine.pager.to(engine.page + (dir ? 1 : -1));
    },

    endMotionScale() {
        // Check minimum scale
        if (engine.elProperties.scale < engine.options.pinchMin) {
            engine.pager.to(engine.page);
        }
    },

    endMotionHandleSlide(speedX: number, speedY: number) {
        if (!engine.options.ending) return;
        if (Math.abs(speedX) < 0.1 && Math.abs(speedY) < 0.1) {
            engine.endMotionHandleSlideEnd();
            return;
        }

        const targetX = speedX * constant.ratio;
        const targetY = speedY * constant.ratio;
        const elStartPos = Object.assign({}, engine.elProperties);
        const elNextPos = Object.assign({}, elStartPos);

        let index = 0;
        let count = EASING.length;
        engine.intervalEnding = window.setInterval(() => {
            const data = EASING[index++];

            elNextPos.x = elStartPos.x + targetX * data;
            elNextPos.y = elStartPos.y + targetY * data;
            // fix out of bound
            engine.flagOutOfBound = engine.util.getPosFixOutOfBound(
                engine.elProperties, elNextPos, engine.posItemInit);
            Object.assign(engine.elProperties, elNextPos);
            engine.updateElPos();
            // index++;

            if (index >= count) {
                engine.endMotionHandleSlideEnd();
                window.clearInterval(engine.intervalEnding);
            }
        }, 350 / count);
    },
    
    /**
     * Make sure image in the viewport.
     */
    endMotionHandleSlideEnd() {
        engine.fixInBound();
    },

    fixInBound() {
        const diff = engine.util.getPosFixOutOfBoundAtEnding(engine.posItemInit);
        if (Math.ceil(diff.x) != 0 || Math.ceil(diff.y) != 0) {
            engine.withAnimate();
            engine.elProperties.x += diff.x;
            engine.elProperties.y += diff.y;
            engine.updateElPos();
            return false;
        } else {
            return true;
        }
    },

    updateElPos() {
        engine.el.style.setProperty('transform',
            `translate(${engine.elProperties.x}px, ${engine.elProperties.y}px) scale(${engine.elProperties.scale})`);
    },

    withAnimate() {
        engine.el.classList.add('animate');
    },

    animateEnd() {
        engine.el.classList.remove('animate');
        // 
        engine.fixInBound();
    },

    emmitJumpPage(page) { },
    pager: {
        count() {
            const itemAll = engine.el.querySelectorAll(`div.${NAME.CSS_PIC}`);
            return itemAll.length;
        },
        to(pageNum, withoutAnimate = false) {
            const elProperties = engine.posElInit
            const size = engine.pager.count();
            if (pageNum > size) {
                pageNum = size;
            } else if(pageNum < 1) {
                pageNum = 1;
            }
            if (pageNum == engine.page) {
                // engine.fixInBound();
                // return;
            }
            // const itemTo = itemAll[pageNum - 1];
            // const boundWrap = engine.wrapperBound;
            // const translateX = (elProperties.width - WIDTHLOADING) / size * (1 - pageNum);

            engine.event.clearDoingType();
            engine.event.jumping = true;

            // const translateX = engine.el.clientWidth / size * (1 - pageNum);
            const translateX =  engine.posItemInit.width * (1 - pageNum);
            // const translateX = engine.posItemInit.width * (1 - pageNum);
            // + widthSpliter) * (pageNum - 1)
                // + (boundWrap.width - elProperties.width) / 2;
            // const translateY = (boundWrap.height - elProperties.height) / 2;
            const translateY = (engine.el.clientHeight - elProperties.height) / 2;
            Object.assign(engine.elProperties, {
                scale: 1,
                x: translateX,
                y: translateY,
            });
            if (!withoutAnimate)
                engine.withAnimate();
            engine.updateElPos();
            engine.page = pageNum;
            engine.pageItem = engine.util.getItem(pageNum);
            engine.emmitJumpPage(pageNum);
        },
        zoom(scale) {
            const diffScale = scale / engine.elProperties.scale;
            engine.zoom(diffScale);
        }
    },

    event: {
        moving: false,
        scaling: false,
        jumping: false,
        clearDoingType() {
            engine.event.moving = false;
            engine.event.scaling = false;
            engine.event.jumping = false;
        },
        start(e) {
            // init
            engine.event.clearDoingType();
            clearInterval(engine.intervalEnding);
            clearTimeout(engine.timeoutDouble);
            engine.flagOutOfBound = false;

            const touchPoses = engine.util.getTouchesPos(e);
            if ( engine.lastTouchStartPos.length > 0
                && e.timeStamp - engine.lastTouchStartPos[0].timestamp < 300) {
                engine.timeoutDouble = window.setTimeout(() => {
                    engine.event.double(touchPoses[0])
                }, 200);
                return;
            }
            engine.event.scaling = false;
            engine.lastTouchStartPos = touchPoses;
            engine.lastTouchPos = touchPoses;
            Object.assign(engine.elProperties, engine.util.getElPos(engine.el));
            Object.assign(engine.lastTouchStartElPos, engine.elProperties);
            //
            const itemPage = engine.util.getItem();
            // const itemAll = engine.el.querySelectorAll(`div.${NAME.CSS_PIC}`);
            // const itemPage = itemAll[engine.page - 1];
            engine.lastTouchStartItemBound = engine.util.getElPos(itemPage.querySelector("img"));
        },
        move(e) {
            e.preventDefault();
            e.stopPropagation();
            clearTimeout(engine.timeoutDouble);

            const touchPos = engine.util.getTouchesPos(e);

            if (touchPos.length == 1 && !engine.event.scaling) {
                if (!engine.event.moving) {
                    engine.event.moving = true;
                }
                // record speed for ending.
                engine.lastCenterPosDiff = engine.util.offsetCenterDiff(touchPos, engine.lastTouchPos);
                engine.move(touchPos);
            } else if(engine.options.pinch && touchPos.length > 1) {
                if (!engine.event.scaling) {
                    engine.scaleEventBefore(touchPos);
                    engine.event.scaling = true;
                }
                engine.scale(touchPos);
                // engine.scaleLastTouchPos = touchPos;
            }
            // record event position
            engine.lastTouchPos = touchPos;
        },

        end(e: TouchEvent) {
            const touchPoses = engine.util.getTouchesPos(e);
            if (engine.event.moving) {
                // engine.event.moving = false;
                engine.endMotion(touchPoses);
            } else if (engine.event.scaling) {
                engine.endMotionScale();
            }
        },

        double(touchPos) {
            engine.zoom(2, touchPos);
        },

        transitionEnd(e) {
            engine.animateEnd();
        }
    },

    util: {
        getRect(el) {
            const rect = el.getBoundingClientRect();
            const offset = [
                Math.max(document.documentElement.scrollLeft, document.body.scrollLeft),
                Math.max(document.documentElement.scrollTop, document.body.scrollTop)
            ];
            return {
                left: rect.left + offset[0],
                top: rect.top + offset[1],
                right: rect.right + offset[0],
                bottom: rect.bottom + offset[1],
                x: rect.x + offset[0],
                y: rect.y + offset[1],
                width: rect.width,
                height: rect.height
            } as DOMRect;
        },
        getElPos(el: HTMLElement) {
            const bounding = engine.util.getRect(el);
            const style = window.getComputedStyle(el);
            let matrixValues = ["", "", "", "1", "0", "0"];
            if (style.transform && style.transform != "none") {
                matrixValues = style.transform.match(/matrix.*\((.+)\)/)[1].split(', ') as string[];
            }
            const pos = Object.assign({}, {
                scale: +matrixValues[3],
                x: +matrixValues[4],
                y: +matrixValues[5],
                // rect
                width: bounding.width,
                height: bounding.height,
                left: bounding.left,
                right: bounding.right,
                top: bounding.top,
                bottom: bounding.bottom,
            });
            return pos as ControlTransform;
        },
        getTouchesPos(e: TouchEvent) {
            const touches: TouchList = e.touches;
            const timestamp = e.timeStamp;
            return Array.prototype.map.call(touches, (t: Touch) => ({ x: t.pageX, y: t.pageY, timestamp }));
        },
        /**
         * single touch
         * changedTouches was better
         * @param touchPos 
         */
        // offsetPosWithEl(touchPos: TouchPos, lastPos: TouchPos = engine.lastTouchPos[0]) {
        //     let x = touchPos.x - lastPos.x + engine.elProperties.x;
        //     let y = touchPos.y - lastPos.y + engine.elProperties.y;
        //     x = Math.round(x);
        //     y = Math.round(y);
        //     return { x, y };
        // },
        // calc two point differet
        offsetCenterDiff(nowPos: TouchPos[], lastPos: TouchPos[]): TouchPos {
            const nowTouchPos: Pos = engine.util.getGestureCenterPos(nowPos);
            const prevTouchPos: Pos = engine.util.getGestureCenterPos(lastPos);
            let timeDiff = 0;
            if (nowPos[0].timestamp && engine.lastTouchPos[0].timestamp) {
                timeDiff = nowPos[0].timestamp - engine.lastTouchPos[0].timestamp;
            }
            const dx = nowTouchPos.x - prevTouchPos.x;
            const dy = nowTouchPos.y - prevTouchPos.y;
            return {
                x: dx,
                y: dy,
                timestamp: Math.round(timeDiff),
                // diameter: Math.abs(Math.round(Math.sqrt(dx**2 + dy**2))),
                diameter: 0,
            }
        },
        getGestureCenterPos(touchPos: TouchPos[]): TouchPos {
            if (touchPos.length > 1) {
                const { x: x0, y: y0 } = touchPos[0];
                const { x: x1, y: y1 } = touchPos[1];
                return { 
                    x: ((x0 + x1) / 2),
                    y: ((y0 + y1) / 2),
                    timestamp: touchPos[0].timestamp,
                    diameter: Math.abs(Math.round(Math.sqrt((x0 - x1)**2 + (y0 - y1)**2))),
                };
            } else {
                return touchPos[0];
            }
        },
        getItem(pageNum: number = engine.page) {
            const pageIndex = pageNum - 1;
            const itemAll = engine.el.querySelectorAll(`div.${NAME.CSS_PIC}`);
            if (itemAll.length <= pageIndex) {
                return null;
            }
            const itemPage = itemAll[pageIndex];
            return itemPage as HTMLElement;
        },
        // Scale number must bigger than one.
        getPosFixOutOfBound(elPro, nextPos, fixBound) {
            // const offsetBoundFix: Pos = { x: 0, y: 0 };
            let flag = false;
            const itemBound = engine.util.getElPos(engine.util.getItem());
            // const limitMoving = itemBound.width / 2;
            const limitMoving = fixBound.width / 2;
            const itemDiff = {
                x: nextPos.x - elPro.x,
                y: nextPos.y - elPro.y
            };
            const itemWillDiff: Pos = Object.assign({}, itemDiff);
            const itemNextBound = Object.assign({}, itemBound, {
                left: itemBound.left + itemDiff.x,
                right: itemBound.right + itemDiff.x,
                top: itemBound.top + itemDiff.y,
                bottom: itemBound.bottom + itemDiff.y,
            });

            // LEFT
            if (itemNextBound.left > fixBound.left) {
                if (itemDiff.x > 0) {
                    itemWillDiff.x = engine.util.numberLevelDown(
                            itemDiff.x,
                            (itemNextBound.left - fixBound.left) / limitMoving
                    );
                }
                flag = true;
            // RIGHT
            } else if (itemNextBound.right < fixBound.right) {
                // offsetBoundFix.x = fixBound.right - itemNextBound.right;
                if (itemDiff.x < 0) {
                    itemWillDiff.x = engine.util.numberLevelDown(
                        itemDiff.x,
                        (fixBound.right - itemNextBound.right) / limitMoving
                    );
                }
                flag = true;
            }

            // TOP
            if (itemNextBound.top > fixBound.top) {
                // offsetBoundFix.y = fixBound.top - itemNextBound.top;
                if (itemDiff.y > 0) {
                    itemWillDiff.y = engine.util.numberLevelDown(
                        itemDiff.y,
                        (itemNextBound.top - fixBound.top) / limitMoving
                    );
                }
                flag = true;
            // BOTTOM
            } else if (itemNextBound.bottom < fixBound.bottom) {
                // offsetBoundFix.y = fixBound.bottom - itemNextBound.bottom;
                if (itemDiff.y < 0) {
                    itemWillDiff.y = engine.util.numberLevelDown(
                        itemDiff.y,
                        (fixBound.bottom - itemNextBound.bottom) / limitMoving
                    );
                }
                flag = true;
            }
            // console.log(offsetBoundFix);
            nextPos.x = elPro.x + itemWillDiff.x;
            nextPos.y = elPro.y + itemWillDiff.y;
            // offsetBoundFix.x += itemWillDiff.x;
            // offsetBoundFix.y += itemWillDiff.y;

            // return offsetBoundFix;
            return flag;
        },
        getPosFixOutOfBoundAtEnding(fixBound) {
            const itemWillDiff = { x: 0, y: 0 };
            const itemBound = engine.util.getElPos(engine.util.getItem());
            if (itemBound.left > fixBound.left) {
                itemWillDiff.x = fixBound.left - itemBound.left;
            } else if (itemBound.right < fixBound.right) {
                itemWillDiff.x = fixBound.right - itemBound.right;
            }
            if (itemBound.top > fixBound.top) {
                itemWillDiff.y = fixBound.top - itemBound.top;
            } else if(itemBound.bottom < fixBound.bottom) {
                itemWillDiff.y = fixBound.bottom - itemBound.bottom;
            }
            return itemWillDiff;
        },
        numberLevelDown(num, per) {
            per = Math.abs(per);
            if (per < 0.1) {
                return num * 0.4;
            } else if (per < 0.2) {
                return num * 0.2;
            } else if (per < 0.3) {
                return num * 0.08;
            } else if (per < 0.5) {
                return num * 0.04;
            } else if (per < 0.8) {
                return num * 0.02;
            } else {
                return 0;
            }
        },
        diffInFixBound() {
            const itemBound = engine.util.getElPos(engine.util.getItem());
            const fixBound = engine.posItemInit;
            return {
                left: itemBound.left - fixBound.left,
                right: itemBound.right - fixBound.right,
                top: itemBound.top - fixBound.top,
                bottom: itemBound.bottom - fixBound.bottom
            };
        }
    }
};

export default engine;